/*
 * Created on Jun 6, 2009
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package ro.qi.framework.sys.scheduler;

import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;

import ro.qi.framework.sys.debug.Logger;
import ro.qi.framework.sys.scheduler.entities.SchedulerTask;
import ro.qi.framework.sys.scheduler.entities.SchedulerTaskCollection;

/**
 * @author George Pogorelschi
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class SchedulerManager extends Thread {
	
	private static final long THREAD_TIMEOUT = 60000; 
	
	private boolean isRunning = false;

	
	private boolean _debug = false;

	private static Object lock = new Object();

	private Date now = new Date();	
	private Hashtable taskIds = null;

	public SchedulerManager() {
		taskIds = new Hashtable();
	}

	//	This method is called when the thread runs
	public void run() {
		setRunning(true);
		
		while (isRunning()) {
			synchronized(lock) {
//				System.out.println("runTasks()");
//				runTasks();
			}
			try {
				sleep(THREAD_TIMEOUT);
			} catch (InterruptedException e) {}
		}

	}

	public void setRunning(boolean status) {
		isRunning = status;
	}
	
	public boolean isRunning() {
		return isRunning;
	}
	
	/*
	 * 
	 */
	private void runTasks() {
		now = new Date();
		
		SchedulerTaskCollection tasks = new SchedulerTaskCollection();
		
		Enumeration enum1 = taskIds.keys();

		while(enum1.hasMoreElements() ) {
			SchedulerTask task = (SchedulerTask)taskIds.get(enum1.nextElement());

			// if tasks start time is is before now
			if (task.getStartTime().before(now)) {

				// if tasks is not already running
				if (task.getState() == SchedulerTask.STATE_IDLE || task.getState() == SchedulerTask.STATE_RESCHEDULED) {

					if (task.getFailedAttempts() < task.getRetryAttempts()) {
						// set state to running
						task.setState(SchedulerTask.STATE_RUNNING);
						// save attempt in case the task fail
			//			task.setRetryAttempts(task.getRetryAttempts()+1);
						task.update();
				
						boolean taskSuccessfull = false;
	
						// run task;
						try {
							getCommand(task).processCommand();

							Logger.debug(this, "Running task \"" + task.getName() +"\": successfull.");
					
							// set state to iddle
							task.setState(SchedulerTask.STATE_IDLE);
							// use the task interval
							Calendar cal = Calendar.getInstance();
							cal.add(Calendar.SECOND, task.getInterval());
							// then set the new start time
							task.setStartTime(cal.getTime());
							// reset failed attempts
							task.setFailedAttempts(0);
							
						} catch (SchedulerException exception) {

							Logger.debug(this, "Running task \"" + task.getName() +"\": failed. Error message: " + exception.getMessage());
					
							// set state to iddle
							task.setState(SchedulerTask.STATE_RESCHEDULED);
							// if task failed use the retry interval
							Calendar cal = Calendar.getInstance();
							cal.add(Calendar.SECOND, task.getRetryInterval());
							// then set the new start time
							task.setStartTime(cal.getTime());
							// increment failed attempts
							task.setFailedAttempts(task.getFailedAttempts() + 1);

						}
				
						// save task
						task.update();
					} else {
						task.setState(SchedulerTask.STATE_STOPED);
						task.update();
						Logger.debug(this, "Task \"" + task.getName() +"\" has reach the failed attempts limit.");
					}
				} else {
					if (task.getState() == SchedulerTask.STATE_RUNNING) {
						Logger.debug(this, "Task \"" + task.getName() +"\" is already running.");
					} else {
						Logger.debug(this, "Task \"" + task.getName() +"\" is stoped.");
					}
				}
			}
		}

	}

	public SchedulerCommand getCommand(SchedulerTask task) {

		if (task.getCommand() != null && task.getCommand().length() > 0) {

			try {
				SchedulerCommand helper = (SchedulerCommand)Class.forName(task.getCommand()).newInstance();
				return helper;
			} catch (ClassNotFoundException e) {
				Logger.error(this, "Task command class " + task.getCommand() + " not found for task " + task.getName() + ": " + e.getMessage());
			} catch (InstantiationException e) {
				Logger.error(this, "Error instantiating the task command class " + task.getCommand() + " for template " + task.getName() + ": " + e.getMessage());
			} catch (IllegalAccessException e) {
				Logger.error(this, "Illegal access for task command class " + task.getCommand() + " for template " + task.getName() + ": " + e.getMessage());
			} 

		}

		return null;

	}

	/*
	 * 
	 */
	public void checkForUpdates() {

		taskIds = new Hashtable();

		SchedulerTaskCollection tasks = new SchedulerTaskCollection();
		
		int taskCount = 0;
		
		Logger.debug(this, "Caching tasks for scheduler (" + tasks.getCollectionSize() + " found):");
		
		for (int i=0; i<tasks.getCollectionSize(); i++) {
			SchedulerTask task = tasks.getTask(i);
			
			// if task is active
			if (task.isActive()) {
				
				taskIds.put(new Integer(taskCount), task);
				
				taskCount++;
				Logger.debug(this, "Added task \"" + task.getName() + "\" to scheduler cache");
			}

		}

		Logger.debug(this, taskCount + " tasks added.");

		runTasks();
	}

}
